
local CGButton = CGButton or {}
CGButton.__index = CGButton

function CGButton.new()
    local self = setmetatable({}, CGButton)
    self.inputs = {}
    self.outputs = {}
    self.nexts = {}
    self.screenHeight = Amaz.BuiltinObject:getInputTextureHeight()
    self.screenWidth = Amaz.BuiltinObject:getInputTextureWidth()
    self.I_Entity = nil
    self.transform2d = nil
    self.camera = nil
    self.isEnable = nil
    self.tap_startPoint = Amaz.Vector2f(0.0, 0.0)
    return self
end

function CGButton:setNext(index, func)
    self.nexts[index] = func
end

function CGButton:setInput(index, func)
    self.inputs[index] = func
end

function CGButton:getOutput(index)
    return self.outputs[index]
end

function CGButton:execute(index)
    if self.inputs[1] == nil or self.inputs[2] == nil then
        return
    end
    self.I_Entity = self.inputs[1]()
    self.camera = self.inputs[2]()
    if self.I_Entity == nil or self.camera == nil then
        return
    end
    self.isEnable = self.inputs[3]() or false

    self.transform2d = self.I_Entity:getComponent("Transform")
end

function CGButton:onEvent(sys, event)
    self.I_Entity = self.inputs[1]()
    self.isEnable = self.inputs[3]() or false
    self.transform2d = self.I_Entity:getComponent("Transform")
    if event.type == Amaz.EventType.TOUCH then
        local touch = event.args:get(0)
        if touch.type == Amaz.TouchType.TOUCH_BEGAN then
            self.tap_startPoint = Amaz.Vector2f(touch.x, touch.y)
            if self.isEnable == true then 
                self:callback(nil, self.tap_startPoint, nil)
            end
        end
    end
end

function CGButton:callback(userData, sender, eventType)
    if sender ~= nil then
        --get sprite world pos
        local worldPosArray = self.transform2d:getWorldRectPosArray()
        if worldPosArray:size() ~= 4 then
            return
        end
        local bottomleft = worldPosArray:get(0)
        local bottomright = worldPosArray:get(1)
        local topleft = worldPosArray:get(2)
        local topright = worldPosArray:get(3)

        --get camera matrix
        local cameraToWorld = self.camera:getCameraToWorldMatrix()
        local worldToCamera = cameraToWorld:invert_Full()

        -- convert world pos
        local convert_bl = worldToCamera:multiplyPoint3(bottomleft)
        local convert_br = worldToCamera:multiplyPoint3(bottomright)
        local convert_tl = worldToCamera:multiplyPoint3(topleft)
        local convert_tr = worldToCamera:multiplyPoint3(topright)

        -- world to pixel
        local bl_x_pixel = convert_bl.x * self.screenHeight / 2
        local bl_y_pixel = convert_bl.y * self.screenHeight / 2
        local br_x_pixel = convert_br.x * self.screenHeight / 2
        local br_y_pixel = convert_br.y * self.screenHeight / 2
        local tl_x_pixel = convert_tl.x * self.screenHeight / 2
        local tl_y_pixel = convert_tl.y * self.screenHeight / 2
        local tr_x_pixel = convert_tr.x * self.screenHeight / 2
        local tr_y_pixel = convert_tr.y * self.screenHeight / 2

        -- pixel to normalized
        local transMatrix = Amaz.Matrix3x3f(
            1, 0, 0.5,
            0, -1, 0.5,
            0, 0, 1)
        local bl_pixel_vector3f = Amaz.Vector3f(bl_x_pixel / self.screenWidth, bl_y_pixel / self.screenHeight, 1)
        local br_pixel_vector3f = Amaz.Vector3f(br_x_pixel / self.screenWidth, br_y_pixel / self.screenHeight, 1)
        local tl_pixel_vector3f = Amaz.Vector3f(tl_x_pixel / self.screenWidth, tl_y_pixel / self.screenHeight, 1)
        local tr_pixel_vector3f = Amaz.Vector3f(tr_x_pixel / self.screenWidth, tr_y_pixel / self.screenHeight, 1)

        local bl_norm_vector3f = transMatrix:multiplyVector3(bl_pixel_vector3f)
        local br_norm_vector3f = transMatrix:multiplyVector3(br_pixel_vector3f)
        local tl_norm_vector3f = transMatrix:multiplyVector3(tl_pixel_vector3f)
        local tr_norm_vector3f = transMatrix:multiplyVector3(tr_pixel_vector3f)

        -- calcute the bounding box

        local pt = {}
        pt[1] = Amaz.Vector2f(bl_norm_vector3f.x, bl_norm_vector3f.y)
        pt[2] = Amaz.Vector2f(br_norm_vector3f.x, br_norm_vector3f.y)
        pt[3] = Amaz.Vector2f(tl_norm_vector3f.x, tl_norm_vector3f.y)
        pt[4] = Amaz.Vector2f(tr_norm_vector3f.x, tr_norm_vector3f.y)

        local minx = pt[1].x
        local maxx = pt[1].x
        local miny = pt[1].y
        local maxy = pt[1].y

        for i = 2,4 do
            if pt[i].x < minx then
                minx = pt[i].x
            end
            if pt[i].x > maxx then
                maxx = pt[i].x
            end
            if pt[i].y < miny then
                miny = pt[i].y
            end
            if pt[i].y > maxy then
                maxy = pt[i].y
            end
        end

        local width = maxx - minx
        local height = maxy - miny
        local rectPt = Amaz.Vector2f(minx, miny)
        self.rect_boundingbox = Amaz.Rect(rectPt.x, rectPt.y, width, height)
        local rect = self.rect_boundingbox
        local drag_pt = Amaz.Vector2f(sender.x, sender.y)
        local pt_x = drag_pt.x
        local pt_y = drag_pt.y

        local tl_x = rect.x
        local tl_y = rect.y
        if (rect.width <= 0 or rect.height <= 0) then
            return
        end
        local bl_x = rect.x
        local bl_y = rect.y + rect.height
        local tr_x = rect.x + rect.width
        local tr_y = rect.y
        local br_x = rect.x + rect.width
        local br_y = rect.y + rect.height

        local a = (tr_x - tl_x) * (pt_y - tl_y) - (tr_y - tl_y) * (pt_x - tl_x)
        local b = (br_x - tr_x) * (pt_y - tr_y) - (br_y - tr_y) * (pt_x - tr_x)
        local c = (bl_x - br_x) * (pt_y - br_y) - (bl_y - br_y) * (pt_x - br_x)
        local d = (tl_x - bl_x) * (pt_y - bl_y) - (tl_y - bl_y) * (pt_x - bl_x)

        
        self.outputs[1] = Amaz.Vector2f(self.rect_boundingbox.x + self.rect_boundingbox.width / 2,self.rect_boundingbox.y + self.rect_boundingbox.height / 2)
        if ((a > 0 and b > 0 and c > 0 and d > 0) or (a < 0 and b < 0 and c < 0 and d < 0)) then
            if self.isEnable == true and self.nexts[0] then
                self.nexts[0]()
            end
        end

    end
end

return CGButton